import 'reflect-metadata'

const REQUIRED_PARAMETERS = 'REQUIRED_PARAMETERS'

/**
 * 方法装饰器
 * @param target 类的原型方法上使用时是原型 类的静态方法上使用时是类本身
 * @param propertyKey 方法名
 * @param descriptor 属性描述符
 */
function validateParameters(target: any, propertyKey, descriptor) {
  const originalMethod = descriptor.value // 通过属性描述符获取函数体
  // 重写属性描述符中的 value 函数体
  descriptor.value = function (...args: any[]) {
    // 从原型的方法上取 REQUIRED_PARAMETERS 元数据 如果没有就是空数组
    const existingRequiredParameters: number[] = Reflect.getOwnMetadata(REQUIRED_PARAMETERS, target, propertyKey) || []
    // 获取 existingRequiredParameters 数组中每个需要验证的方法参数对应的索引
    for (let parameterIndex of existingRequiredParameters) {
      if (args[parameterIndex] === undefined) { // 如果索引对应的参数为 undefined 则向外提示该参数没有传递
        console.log(parameterIndex, '参数没有传递')
      }
    }
    console.log(this, this===user, 'this')
    return originalMethod.apply(this,  args) 
  }
}
/**
 * 参数装饰器
 * @param target 类的原型方法上的参数装饰器是原型对象 类的静态方法上的参数装饰器是类本身
 * @param propertyKey 方法名
 * @param parameterIndex 参数索引 从左往右 从0开始
 */
function validate(target: any, propertyKey: string, parameterIndex: number) {
  // console.log(target, propertyKey, parameterIndex) // 类的原型 方法名 参数索引
  // 第一次取是 []
  const existingRequiredParameters: number[] = Reflect.getOwnMetadata(REQUIRED_PARAMETERS, target, propertyKey) || []
  // 将参数索引保存到 existingRequiredParameters 数组中
  existingRequiredParameters.push(parameterIndex)
  // 给原型的方法添加一个 REQUIRED_PARAMETERS 元数据 值是 existingRequiredParameters 数组
  Reflect.defineMetadata(REQUIRED_PARAMETERS, existingRequiredParameters, target, propertyKey)
}

class User {
  @validateParameters
  setName(@validate newName: string) {

  }
}

const user = new User

user.setName('ls') // 调用方法会执行方法装饰器
user.setName(undefined) // 方法装饰器验证失败
